﻿using System;
using System.Collections;
using System.Collections.Generic;
using GTA;
using offline2048;
using UnityEngine;
using pooling;
using Random = UnityEngine.Random;

public class GameManager : MonoBehaviour
{
    public static GameManager instance;

    public GameObject CellPrefab;
    public CurrentCellImage CurrentImage;
    public Transform PlayerField;
    public Color[] ColorArray;
    public int ReviveCostCoin;
    public float UnitScale; // 1.7f
    public float UnitBlack; // 0.1f
    public GameData CurrentData;

    #region Custom Parameter;
    [Space]
    [Tooltip("Game Parameter")]
    public int ScoreBonusUnit = 1;

    [SerializeField]
    private readonly int maxColumnNumber= 5;
    [SerializeField]
    private readonly int maxRowNumber = 7;
    [SerializeField]
    private readonly int maxCellNumber = 35;
    #endregion

    public List<Sprite> m_BlockImageList;
    
    private Pooling<Cell> cellPool = new Pooling<Cell>();
    private Cell[,] cellArray; // [5,7]
    private List<List<Cell>> linkCellList = new List<List<Cell>>();

    public int currentCellNumber = 0;
    public int bestScore = 0;
    private int resumeTime = 2;
    private int cellCounter = 0;
    private int currentMaxCellNumber = 0;
    private int fusionContinueNumber = 0;
    private bool gameFailed = false;
    private bool shootAble = true;
    private bool hasGem = false;
    private Vector3 startPosition = Vector3.zero;
    //存储用=========================================================================
    private const string GIFT_BOX_SHUTDOWN_TIME = "Gift_Box_Shutdown_Time";
    
    private void Awake()
    {
        instance = this;
    }

    // Start is called before the first frame update
    void Start()
    {
        cellPool.createMoreIfNeeded = true;
        cellPool.Initialize(CellPrefab, PlayerField);

        StartGame();
    }
    
    public void  StartGame()
    {
        startPosition = new Vector3((-UnitScale - UnitBlack) * ((float)maxColumnNumber - 1) / 2, 2f + (UnitScale + UnitBlack) * ((float)maxRowNumber - 1) / 2, 0);
        cellArray = new Cell[maxColumnNumber, maxRowNumber];

        LoadGameData();
        CreateCurrentCell();
    }

    private void GameFail()
    {
        shootAble = false;
        gameFailed = true;

        /*if (resumeTime > 0)
        {
            UIManager.instance.ShowBox(UIBoxType.ResumePanel);
        }
        else
        {
            UIManager.instance.ShowBox(UIBoxType.FailPanel);
            resumeTime = 2;
        }*/
        int isFirst = PlayerPrefs.GetInt("f7jryj", 0);
        if (isFirst == 0)
        {
            PlayerPrefs.SetInt("f7jryj", 1);
            AdjustWrapper.Instance.LogEvent("f7jryj", null);
        }
        UIManager.instance.ShowBox(UIBoxType.FailPanel);
        if (bestScore < CurrentData.BestScore)
        {
            bestScore = CurrentData.BestScore;
        }
    }

    public void AddInitCoin()
    {
        CurrentData.CoinNumber = 100;
    }
    
    public bool BuyResumeGame()
    {
        if(CurrentData.CoinNumber >= ReviveCostCoin)
        {
            CurrentData.CoinNumber -= ReviveCostCoin;
            ResumeGame();
            return true;
        }
        else
        {
            return false;
        }
    }

    public void ResumeGame()
    {
        DestroyHalfLine();
        shootAble = true;
        gameFailed = false;
        
        resumeTime--;
    }
    
    public void RestartGame()
    {
        cellPool.ReleaseAll();
        RefreshCellArray();
        linkCellList.Clear();
        resumeTime = 2;
        cellCounter = 0;
        CurrentData.CurrentScore = 0;
        shootAble = true;
        gameFailed = false;

        CreateCurrentCell();
    }

    private void OnApplicationPause(bool pause)
    {
        if(pause)
        {
            SaveGameData();
        }
    }

#if UNITY_EDITOR
    private void OnApplicationQuit()
    {
        SaveGameData();
    }
#endif

    #region Game Function
    private void RefreshCellArray()
    {
        for (int i = 0; i < maxColumnNumber; i++)
        {
            for (int j = 0; j < maxRowNumber; j++)
            {
                cellArray[i, j] = null;
            }
        }
    }
    
    public void OnColumnClick(int column)
    {
        if (!shootAble) return;

        if (column == -1) return; //point no column

        int index = maxRowNumber;
        while(index > 0 && cellArray[column, index - 1] == null)
        {
            index--;
        }

        if (UserLayerManager.Instance.GetCurrentUserLayer() == UserLayerManager.UserLayerType.None)
        {
            int _count = PlayerPrefsManager.GetInt(PlayerPrefsManager.USER_CHANGE_LAYER_TIME, 0);
            _count++;
            if (_count > 6)
            {
                //UserLayerManager.Instance.ChangeUserLayerByGM(UserLayerManager.UserLayerType.Install);
                if (UserLayerManager.Instance.GetCurrentUserLayer() == UserLayerManager.UserLayerType.None)
                {
                    UserLayerManager.Instance.ChangeUserLayer(UserLayerManager.UserLayerType.Organic);	
                }
                
                if (!UserLayerManager.Instance.IsOrganic())
                {
                    if (PlayerPrefsManager.GetInt(PlayerPrefsManager.PLAYER_GUIDE_SHOW_ID,1002) < 1004)
                    {
                        MainManager.Instance.ShowUIGuide();
                    }
                }
                EventManager2.SetUIActiveByUserLayer();
            }
            PlayerPrefsManager.SetInt(PlayerPrefsManager.USER_CHANGE_LAYER_TIME, _count);
        }
        
        if (index < maxRowNumber)
        {
            shootAble = false;
            AddCurrentCell(column, index, currentCellNumber);
        }
        
    }

    public void OnCurrentCellStop(int column, int row)
    {
        CreateCurrentCell();

        CheckLinkByDirection(column, row);

        DestroyLinkCellCheck();
    }

    public void CreateCurrentCell()
    {
        currentCellNumber = Random.Range(1, 7);
        hasGem = (Random.Range(0, 50) == 0);
        CurrentImage.InitCurrent(currentCellNumber,GetColorByNumber(currentCellNumber), hasGem);
    }

    public void CreateCurrentCell(int Number)
    {
        currentCellNumber = Number;
        hasGem = (Random.Range(0, 50) == 0);
        CurrentImage.InitCurrent(currentCellNumber,GetColorByNumber(currentCellNumber), hasGem);
    }
        
    public void AddCurrentCell(int column, int row, int number)
    {
        AudioController.Play("Swipe");
        Cell newCell = cellPool.Collect();
        cellArray[column, row] = newCell;
        

        newCell.InitCell(GetColorByNumber(number), number, GetPositionByGrid(column, maxRowNumber - 1), GetPositionByGrid(column, row), column, row, true);

        if (hasGem)
        {
            newCell.AttachGem();
        }

        cellCounter++;
    }
    
    private void SpawnCellByGrid(int column, int row, int number)
    {
        Cell newCell = cellPool.Collect();
        cellArray[column, row] = newCell;
        

        newCell.InitCell(GetColorByNumber(number), number, GetPositionByGrid(column, maxRowNumber - 1), GetPositionByGrid(column, row), column, row, false);

        //CellCounter++;
    }
    
    private void DestroyLinkCellCheck()
    {
        bool hasDelete = false;

        shootAble = false;

		//目的是Leantween的延迟调用会使Cell的地址错误?动画效果是移动后再增加数字，这个过程中linklist会refresh
        List<Cell> templist = new List<Cell>();
        List<int> gainList = new List<int>();
        int _tempScore = 0;
        for (int i = linkCellList.Count - 1; i >= 0; i--)
        {
            int linkCount = linkCellList[i].Count;

            if (linkCount == 2)
            {
                Vector3 link1Position = linkCellList[i][0].transform.position;
                Vector3 link2Position = linkCellList[i][1].transform.position;

                CurrentData.CurrentScore += linkCellList[i][0].Number + 1;
                _tempScore = linkCellList[i][0].Number + 1;
                if (link1Position.y < link2Position.y - 0.1f || (Mathf.Abs(link1Position.y - link2Position.y) < 0.1f && (Random.Range(0,2) == 0)) ) //如果后出现的在先出现的上方 + 在同排&&随机
                {
                    Cell tempCell = linkCellList[i][0];
                    linkCellList[i][0] = linkCellList[i][1];
                    linkCellList[i][1] = tempCell;
                    
                }

                linkCellList[i][1].FusionCell(linkCellList[i][0].transform.position, 0.15f);

                linkCellList[i].RemoveAt(1);
                cellCounter--;
                fusionContinueNumber++;
                
                templist.Add(linkCellList[i][0]);
                gainList.Add(1);

                hasDelete = true;
            }
            else if(linkCount >= 3)
            {
                Vector3 fusionPosition = linkCellList[i][linkCount - 1].transform.position;

                CurrentData.CurrentScore += linkCellList[i][0].Number + linkCount - 1;
                _tempScore = linkCellList[i][0].Number + linkCount - 1;
                for (int index=0;index< linkCount - 1; index++)
                {
                    linkCellList[i][0].FusionCell(fusionPosition, 0.15f);
                    linkCellList[i].RemoveAt(0);
                    cellCounter--;
                    fusionContinueNumber++;
                }

                templist.Add(linkCellList[i][0]);
                gainList.Add(linkCount - 1);
                hasDelete = true;
            }
        }
        //Debug.Log("===================" + _tempScore);
        if (_tempScore != 0)
        {
            PlayerPrefsManager.SetInt(PlayerPrefsManager.PLAYER_CURRENT_DOLLER_COUNT,_tempScore);
        }
        if (!hasDelete)
        {
            if (cellCounter >= maxCellNumber)
            {
                GameFail();
            }
            else
            {
                if (fusionContinueNumber > 4)
                {
                    AudioController.Play("GreatJob");
                }
                fusionContinueNumber = 0;
                _tempScore = PlayerPrefsManager.GetInt(PlayerPrefsManager.PLAYER_CURRENT_DOLLER_COUNT);
                if (_tempScore >= 8)
                {
                    CurrentData.CurrentTargetNumber = currentMaxCellNumber + 1;
                    EventManager2.OnTargetChange?.Invoke(_tempScore);
                    PlayerPrefsManager.SetInt(PlayerPrefsManager.PLAYER_CURRENT_DOLLER_COUNT,0);
                    ParticleManager.instance.PlayNewBestScoreParticle();

                    if(currentMaxCellNumber >= 109)
                    {
                        currentMaxCellNumber = 0;
                        cellPool.ReleaseAll();
                        RefreshCellArray();
                        linkCellList.Clear();
                        CreateCurrentCell();
                    }
                }
                shootAble = true;
                /*if (currentMaxCellNumber >= CurrentData.CurrentTargetNumber)
                {

                }*/
            }
        }
        else
        {
            LeanTween.delayedCall(0.3f, () =>
            {
                for(int i=0;i<templist.Count;i++)
                {
                    templist[i].GainNumber(gainList[i]);

                    if(templist[i].Number > currentMaxCellNumber)
                    {
                        currentMaxCellNumber = templist[i].Number;
                    }
                }

                CheckUpFill();
            });
        }
        
    }

    public void DestroyHalfLine()
    {
        for (int i = 0; i < maxColumnNumber; i++)
        {
            for (int j = maxRowNumber - 1; j >= maxRowNumber / 3; j--)
            {
                DestroyCellByGrid(i, j);
            }
        }
    }
    
    private void DestroyCellByGrid(int column, int row)
    {
        if (cellArray[column, row] == null) return;

        RemoveLinkByGrid(column, row); // 删除link
        cellArray[column, row].OnRelease(); //隐藏 显示
        cellArray[column, row] = null; //清空数组数据
        cellCounter--;
    }

    public void OnCellFusion(int column, int row)
    {
        cellArray[column, row] = null;
    }

    public void OnHammerUse(Vector3 position)
    {
        Vector3 point = Camera.main.ScreenToWorldPoint(position);
        Cell tempCell = GetGridByPosition(point);
        
        if(tempCell != null)
        {
            EventManager2.OnHammerSuccess?.Invoke(tempCell.transform.position);
            LeanTween.delayedCall(1f, () =>
            {
                DestroyCellByGrid(tempCell.Column, tempCell.Row);
                ParticleManager.instance.PlayHammerParticle(tempCell.transform.position);
                CurrentData.CoinNumber -= 100;
                EventManager2.UpdateCoinChange();
                Invoke("CheckUpFill", 0.2f);
            });
        }
    }

    #endregion

    #region link function
    private void CheckLinkByAll()
    {
        for (int i = 0; i < maxColumnNumber; i++)
        {
            for (int j = 0; j < maxRowNumber; j++)
            {
                if (cellArray[i, j] == null) continue;

                CheckLinkByDirection(i, j);
            }
        }
        DestroyLinkCellCheck();
    }

    private void CheckLinkByDirection(int column, int row)
    {
        if (cellArray[column, row] == null) return;

        if(column > 0)//left
        {
            CheckLinkByGrid(column, row, column - 1, row);
        }

        if (column < maxColumnNumber - 1)//right
        {
            CheckLinkByGrid(column, row, column + 1, row);
        }
        
        if(row > 0)//up
        {
            CheckLinkByGrid(column, row, column, row - 1);
        }

        if (row < maxRowNumber - 1) // down
        {
            CheckLinkByGrid(column, row, column, row + 1);
        }
    }

    private void CheckLinkByGrid(int columnNow, int rowNow, int columnCheck, int rowCheck)
    {
        if (cellArray[columnCheck, rowCheck] != null 
            && cellArray[columnNow, rowNow].Number == cellArray[columnCheck, rowCheck].Number)
        {
            int checkLinkCellListIndex = cellArray[columnCheck, rowCheck].LinkCellListIndex;
            int currentLinkCellListIndex = cellArray[columnNow, rowNow].LinkCellListIndex;
            
            if (checkLinkCellListIndex != -1) // check already link
            {
                if (currentLinkCellListIndex == checkLinkCellListIndex) return; //已经连接了，就不要重复连接

                if(currentLinkCellListIndex != -1)//当前Cell有不同链接,把当前的link合并到check的link 
                {
                    linkCellList[checkLinkCellListIndex].AddRange(linkCellList[currentLinkCellListIndex]);//添加之后 再clear是否把引用也清空了？

                    foreach (Cell c in linkCellList[currentLinkCellListIndex])
                    {
                        c.LinkCellListIndex = checkLinkCellListIndex;
                    }

                    linkCellList[currentLinkCellListIndex].Clear();
                    linkCellList.RemoveAt(currentLinkCellListIndex);
                    
                    RefreshLinkListIndex();
                }
                else  // 当前Cell无连接，将当前cell加入check list
                {
                    cellArray[columnNow, rowNow].LinkCellListIndex = checkLinkCellListIndex;
                    linkCellList[checkLinkCellListIndex].Add(cellArray[columnNow, rowNow]);
                }
            }
            else // check no link
            {
                if (currentLinkCellListIndex != -1)//当前 Cell有连接
                {
                    cellArray[columnCheck, rowCheck].LinkCellListIndex = currentLinkCellListIndex;
                    linkCellList[currentLinkCellListIndex].Insert(0,cellArray[columnCheck, rowCheck]);
                }
                else  // 当前Cell无连接
                {
                    cellArray[columnNow, rowNow].LinkCellListIndex = linkCellList.Count;
                    cellArray[columnCheck, rowCheck].LinkCellListIndex = linkCellList.Count;
                    linkCellList.Add(new List<Cell>() { cellArray[columnCheck, rowCheck], cellArray[columnNow, rowNow] });
                }
            }
        }
    }

    private void CheckUpFill()
    {
        for(int i=0;i<maxColumnNumber;i++) //一列
        {
            for(int j=1;j<maxRowNumber;j++) //一排，先排后列
            {
                if (cellArray[i, j] == null) continue;

                int index = j;
                while(index > 0 && cellArray[i, index - 1] == null)
                {
                    index--;
                }

                if(index < j)
                {
                    RemoveLinkByGrid(i, j);

                    cellArray[i, j].UpFillCell(index, GetPositionByGrid(i, index)); // update grid,position and delete link - 1
                    cellArray[i, index] = cellArray[i, j];
                    cellArray[i, j] = null;
                }
            }
        }

        //更新位置后，重新link
        Invoke("CheckLinkByAll", 0.1f);
        //CheckLinkByAll();
    }
    
    private void RemoveLinkByGrid(int column, int row)
    {
        if (cellArray[column, row].LinkCellListIndex != -1) //移动的Cell有连接
        {
            if (linkCellList[cellArray[column, row].LinkCellListIndex].Count > 1) //移动的Cell连接list中Cell数大于1
            {
                linkCellList[cellArray[column, row].LinkCellListIndex].Remove(cellArray[column, row]);
                cellArray[column, row].LinkCellListIndex = -1;
                
            }
            else //移动的Cell list只有一个Cell
            {
                linkCellList[cellArray[column, row].LinkCellListIndex].Clear();
                linkCellList.RemoveAt(cellArray[column, row].LinkCellListIndex);
                cellArray[column, row].LinkCellListIndex = -1;
                //刷新linklist中Cell的序号
                RefreshLinkListIndex();
            }
        }//移动的Cell没连接，不需要清理list
    }

    private void RefreshLinkListIndex()
    {
        //刷新linkindex
        for (int i = 0; i < linkCellList.Count; i++)
        {
            foreach (Cell c in linkCellList[i])
            {
                c.LinkCellListIndex = i;
            }
        }
    }
    #endregion
    
    public Vector3 GetPositionByGrid(int column, int row)
    {
        Vector3 position = startPosition + new Vector3(UnitScale * column + UnitBlack * column, -UnitScale * row - UnitBlack * row, 0);

        return position;
    }
    
    public Color GetColorByNumber(int number)
    {
        return ColorArray[(number - 1) % ColorArray.Length];
    }

    public Cell GetGridByPosition(Vector3 position)
    {
        Vector3 diff = position - startPosition;
        
        if (diff.x < -UnitScale / 2 || diff.x > (maxColumnNumber - 0.5f) * (UnitScale + UnitBlack)
            ||diff.y > UnitScale / 2 || diff.y < (-maxRowNumber + 0.5f) * (UnitScale + UnitBlack))
        {
            return null;
        }
        else
        {
            int column = Mathf.CeilToInt(diff.x / (UnitScale + UnitBlack) - 0.5f);
            int row = Mathf.FloorToInt(-diff.y / (UnitScale + UnitBlack) + 0.5f);
            return cellArray[column,row];
        }
    }
    //储存逻辑==============================================================================
    public DateTime TimeStampToDateUTC(long timeStamp = 0)
    {
        DateTime startTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
        if (timeStamp == 0)
            timeStamp = GetTimeStamp();
        DateTime dt = startTime.AddMilliseconds(timeStamp);
        return dt;
    }
    
    public long GetTimeStamp()
    {
        TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
        long ret = Convert.ToInt64(ts.TotalMilliseconds);
        return ret;
    }

    public void SaveGiftBoxShutdownTime()
    {
        DateTime dt = TimeStampToDateUTC();
        DateTime newTimestamp = dt.AddHours(24);
        long newTimestampLong = newTimestamp.Ticks;
        PlayerPrefs.SetString(GIFT_BOX_SHUTDOWN_TIME, newTimestampLong.ToString());
    }

    private void InitGiftBoxShutdownTime()
    {
        DateTime dt = TimeStampToDateUTC();
        long newTimestampLong = dt.Ticks;
        PlayerPrefs.SetString(GIFT_BOX_SHUTDOWN_TIME, newTimestampLong.ToString());
    }

    private bool iiii = false;
    public DateTime GetGiftBoxShutdownTime()
    {
        string _time = PlayerPrefs.GetString(GIFT_BOX_SHUTDOWN_TIME, "");
        if (_time.Equals(""))
        {
            InitGiftBoxShutdownTime();
            _time = PlayerPrefs.GetString(GIFT_BOX_SHUTDOWN_TIME, "");
            DateTime timestamp = new DateTime(long.Parse(_time));
            return timestamp;
        }
        else
        {
            DateTime timestamp = new DateTime(long.Parse(_time));
            return timestamp;
        }
    }
    
    //储存逻辑结束===========================================================================
    #region Data Function
    private void  LoadGameData()
    {
        CurrentData = SaveManager.LoadGame();
        //CurrentData = null; 
        if(CurrentData == null)
        {
            int[,] NumberArray = new int[maxColumnNumber, maxRowNumber];
            for (int i = 0;i<maxColumnNumber;i++)
            {
                for(int j = 0;j<maxRowNumber;j++)
                {
                    NumberArray[i, j] = -1;
                }
            }

            CurrentData = new GameData(false, false, true, false, 9, 0, 0, 200, NumberArray);

            LeanTween.delayedCall(0.2f, () =>
            {
                UIManager.instance.ShowTutorial();
            });
        }
        else
        {
            if (CurrentData.GameFail)
            {
                CurrentData.CurrentScore = 0;
                return;
            }

            //spawn record cell and link;
            int recordCellNumber = 0;

            for(int i=0;i<maxColumnNumber;i++)
            {
                for(int j=0;j<maxRowNumber;j++)
                {
                    if (CurrentData.NumberArray[i, j] == -1) continue;

                    recordCellNumber++;
                    SpawnCellByGrid(i, j, CurrentData.NumberArray[i, j]); 
                }
            }

            cellCounter += recordCellNumber;
            bestScore = CurrentData.BestScore;

            CheckLinkByAll();

            LeanTween.delayedCall(0.2f, () =>
            {
                DestroyLinkCellCheck();
            });

        }
    }

    private void SaveGameData()
    {
        for(int i=0;i<maxColumnNumber;i++)
        {
            for(int j=0;j<maxRowNumber;j++)
            {
                if(cellArray[i,j] == null)
                {
                    CurrentData.NumberArray[i, j] = -1;
                }
                else
                {
                    CurrentData.NumberArray[i, j] = cellArray[i, j].Number;
                }
            }
        }
        CurrentData.GameFail = gameFailed;
        
        SaveManager.SaveGame(CurrentData);
    }
    #endregion
}


